package myJs.user.data

import myJs.Implicits._
import myJs.Utils._
import scala.scalajs.js.Dynamic.{global => g}
import myJs.myPkg.{BootstrapValidator, LayerOptions, Select2Options, Swal, SwalOptions}
import myJs.myPkg.bootstrap.Bootstrap.default._
import myJs.myPkg.jquery._
import myJs.tool.Tool
import myJs.tool.Tool._
import org.scalajs.dom.ext.Ajax
import org.scalajs.dom.{Element, document}
import shared.Pojo._

import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scalatags.Text.all._

import scala.scalajs.js.JSON
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._

/** Created by yz on 10/11/2020
  */
object SubModal {

  val modalId = "subModal"
  val formId = "subForm"
  val extraGroupModalId = "extraGroupModal"
  val extraVarInfoModalId = "extraVarInfoModal"

  def init = {
    bootStrapValidator
    registerEvent
  }

  def registerEvent = {
    $(document.body).on(
      "click",
      s"#${modalId} .myExtraGroupShow",
      "",
      (y: Element) => {
        extraGroupShow
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .myExtraVarInfoShow",
      "",
      (y: Element) => {
        extraVarInfoShow
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .myMoveRight",
      "",
      (y: Element) => {
        moveToRight(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .myMoveRightAll",
      "",
      (y: Element) => {
        moveRightAll(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .myMoveLeftAll",
      "",
      (y: Element) => {
        moveLeftAll(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .myMoveLeft",
      "",
      (y: Element) => {
        moveToLeft(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .myReverseMove",
      "",
      (y: Element) => {
        reverseRemove(y)
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .mySub",
      "",
      (y: Element) => {
        sub
      }
    )
    $(document.body).on(
      "click",
      s"#${modalId} .mySort",
      "",
      (y: Element) => {
        sort(y)
      }
    )
  }

  def mySort(vs: List[String]) = {
    val numberVs = vs.filter(_.matches("^\\d+.*$"))
    val noNumberVs = vs.filterNot(numberVs.contains(_))
    val sortedNumberVs = numberVs.sortBy { numberV =>
      val r = "^(\\d+).*$".r
      r.findAllIn(numberV).group(1).toInt
    }
    val sortedNoNumberVs = noNumberVs.sortBy(_.toLowerCase)
    sortedNumberVs ::: sortedNoNumberVs
  }

  def getOptionValues(jq: JQuery) = {
    jq.find("option")
      .mapElems(x => x)
      .map { y =>
        $(y).myVal
      }
      .toList
  }

  def sort(y: Element) = {
    val left = getLeft(y)
    val leftValues = getOptionValues(left)
    val right = getRight(y)
    val rightValues = getOptionValues(right)
    val sortedValues = mySort(leftValues ::: rightValues)
    val indexMap = sortedValues.zipWithIndex.toMap
    val leftHtml = mySort(leftValues)
      .map { v =>
        val i = indexMap(v)
        option(value := s"${v}", dataId := s"${i}", title := s"${v}", v)
      }
      .mkString("&nbsp;")
    left.html(leftHtml)
    val rightHtml = rightValues
      .map { v =>
        val i = indexMap(v)
        option(value := s"${v}", dataId := s"${i}", title := s"${v}", v)
      }
      .mkString("&nbsp;")
    right.html(rightHtml)
  }

  def reverseRemove(y: Element) = {
    val left = getLeft(y)
    val right = getRight(y)
    optionSwap(left, right)
    rowColValid
    refreshNum(y)
  }

  def optionSwap(leftJq: JQuery, rightJq: JQuery) = {
    val tmpJq = $("#tmpExchange")
    tmpJq.empty()
    tmpJq.append(leftJq.children())
    leftJq.append(rightJq.children())
    rightJq.append(tmpJq.children())
  }

  def rowColCheck = {
    rowColValid
    val vys = List("rows[]", "cols[]")
      .map { name =>
        Tool.getInputByName(name)
      }
      .map { y =>
        $(y).myVisVal -> y
      }
    vys.forall(_._1.nonBlank)
  }

  def sub = {
    val bv = $(s"#${modalId} #${formId}").bv
    bv.validate()
    val valid = bv.isValid()
    if (valid && rowColCheck) {
      val element = div(
        id := "content",
        span(id := "info", messages("running"), span(id := "progress", "。。。")),
        " ",
        img(src := "/assets/images/running2.gif", cls := "runningImage", width := 30, height := 20)
      ).render
      val layerOptions = LayerOptions.title(Tool.zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
      val index = layer.alert(element, layerOptions)
      val url = g.jsRoutes.controllers.MatrixFileDataController.sub().url.toString
      val dict = js.Dictionary(
        "fileName" -> $(s"#${modalId}").findInputByName("fileName").myVal,
        "rows" -> $(s"#${modalId}").findInputByName("rows[]").myVisVals.flatMap(_.split(",")),
        "cols" -> $(s"#${modalId}").findInputByName("cols[]").myVisVals.flatMap(_.split(",")),
        "id" -> $(s"#${modalId}").findInputByName("id").myVal
      )
      val data = JSON.stringify(dict)
      Ajax.post(url = s"${url}", data = data, headers = Map("Content-Type" -> "application/json")).map { xhr =>
        val rs = xhr.responseText.toJDJAn
        layer.close(index)
        $(s"#${modalId}").modal("hide")
        MetDataTab.refreshTable { () =>
          val options = SwalOptions(
            `type` = "success",
            title = messages("success"),
            text = messages("AddSuccessfully")
          )
          Swal.swal(options)
        }
      }
    }
  }

  def refreshNum(y: Element): JQuery = {
    refreshLeftNum(y)
    refreshRightNum(y)
  }

  def refreshLeftNum(y: Element) = {
    val left = getLeft(y)
    val num = left.find(">option").size
    val jq = $(y).parents(".myEachGroup").find("#remainNum")
    jq.text(s"${num}")
  }

  def getLeft(y: Element) = {
    $(y).parents(".myEachGroup").find(".myLeft")
  }

  def refreshRightNum(y: Element) = {
    val right = getRight(y)
    val num = right.find(">option").size
    val jq = $(y).parents(".myEachGroup").find("#num")
    jq.text(s"${num}")
  }

  def getRight(y: Element) = {
    $(y).parents(".myEachGroup").find(".myRight")
  }

  def moveLeftAll(y: Element) = {
    val right = getRight(y)
    val rightOptions = right.children(":visible")
    val left = getLeft(y)
    r2l(rightOptions, left)
    refreshNum(y)
  }

  def r2l(rightOptions: JQuery, left: JQuery) = {
    val leftOptions = left.children()
    val leftElems = leftOptions.mapElems(y => y)
    rightOptions.mapElems(y => y).foreach { y =>
      val rightId = $(y).dataId.toInt
      val elemOp = leftElems.find { z =>
        val leftId = $(z).dataId.toInt
        leftId > rightId
      }
      elemOp
        .map { elem =>
          $(y).insertBefore($(elem))
        }
        .getOrElse {
          left.append($(y))
        }
    }
    rowColValid
  }

  def rowColValid = {
    val rowsJq = Tool.getInputByName("rows[]")
    val colsJq = Tool.getInputByName("cols[]")
    val bv = $(s"#${modalId} #${formId}").bv
    List(rowsJq, colsJq).foreach { jq =>
      if (jq.myVisVal.nonBlank) {
        bv.updateStatus(jq, "VALID", "blank")
      } else {
        bv.updateStatus(jq, "INVALID", "blank")
      }
    }
  }

  def leftMoves(metabolites: List[String]) = {
    val leftOptions = $("#left").find(".myLeft").find(":visible")
    val right = $("#left").find(".myRight")
    val needMoveOptions = leftOptions.mapElems(y => y).filter { y =>
      val value = $(y).attr("value").get
      metabolites.contains(value)
    }
    needMoveOptions.foreach { y =>
      right.append($(y))
    }
    rowColValid
    refreshNum($("#left .myExtraVarInfoShow"))
  }

  def refreshNum(jq: JQuery): JQuery = {
    val y = jq(0)
    refreshNum(y)
  }

  def moveRightAll(y: Element) = {
    val leftOptions = getLeft(y).find(":visible")
    val right = getRight(y)
    right.append(leftOptions)
    rowColValid
    refreshNum(y)
  }

  def moveToLeft(y: Element) = {
    val right = getRight(y)
    val rightOptions = right.find("> option:selected")
    val left = getLeft(y)
    r2l(rightOptions, left)
    refreshNum(y)
  }

  def moveToRight(y: Element) = {
    val leftOptions = getLeft(y).find("> option:selected")
    val right = getRight(y)
    right.append(leftOptions)
    rowColValid
    refreshNum(y)
  }

  def rightMoves(sampleIds: List[String]) = {
    val leftOptions = $("#right").find(".myLeft").find(":visible")
    val right = $("#right").find(".myRight")
    val needMoveOptions = leftOptions.mapElems(y => y).filter { y =>
      val value = $(y).attr("value").get
      sampleIds.contains(value)
    }
    needMoveOptions.foreach { y =>
      right.append($(y))
    }
    rowColValid
    refreshNum($("#right .myExtraGroupShow"))
  }

  def extraVarInfoShow = {
    val fileName = $(s"#${modalId} #fileName").text().trim
    val finalFileName = s"${MetDataKind.showDirName}/${fileName}"
    $(s"#${extraVarInfoModalId}").findInputByName("originalMatrixFile").`val`(finalFileName)
    $(s"#${extraVarInfoModalId}").modal("show")
  }

  def extraGroupShow = {
    val fileName = $(s"#${modalId} #fileName").text().trim
    val finalFileName = s"${MetDataKind.showDirName}/${fileName}"
    $(s"#${extraGroupModalId}").findInputByName("file").`val`(finalFileName)
    $(s"#${extraGroupModalId}").modal("show")
  }

  def bootStrapValidator = {

    def dataF: js.Function = (validator: BootstrapValidator) => {
      js.Dictionary(
        "kind" -> validator.getFieldElements("kind").myVal
      )
    }

    val maxNumber = Double.MaxValue
    val url = g.jsRoutes.controllers.MatrixFileDataController.fileNameNonExistCheck().url.toString
    val dict: js.Dictionary[js.Any] = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh"
      ),
      "fields" -> js.Dictionary(
        "rows[]" -> {
          js.Dictionary(
            "validators" -> js.Dictionary(
              "blank" -> js.Dictionary(
                "message" -> s"${messages("null")}"
              )
            )
          )
        },
        "cols[]" -> {
          js.Dictionary(
            "validators" -> js.Dictionary(
              "blank" -> js.Dictionary(
                "message" -> s"${messages("null")}"
              )
            )
          )
        },
        "fileName" -> {
          val info = messages("fileName")
          js.Dictionary(
            "validators" -> js.Dictionary(
              "notEmpty" -> js.Dictionary(
                "message" -> s"${messages("null")}"
              ),
              "remote" -> js.Dictionary(
                "message" -> s"${messages("exist")}",
                "url" -> url,
                "type" -> "POST",
                "delay" -> 1000,
                "data" -> dataF
              )
            )
          )
        }
      )
    )
    $(s"#${modalId} #${formId}").bootstrapValidator(dict)
  }

}
